library(here)
library(DBI)
library(RSQLite)
library(raster)
library(sf)
library(httr) # generic webservice package
library(tmap)
#NASIS tables
# pedon  to siteobs: siteobsiidref==siteobsiid

pedon <- data.table::fread("C:/R_Drive/Data_Files/LPKS_Data/Data/Soil_Pedon_Databases/NRCS/NASIS/NASIS_APRIL_2017/CSV_files/pedon.csv",
    sep = "|", header = T)

siteobs <- data.table::fread("C:/R_Drive/Data_Files/LPKS_Data/Data/Soil_Pedon_Databases/NRCS/NASIS/NASIS_APRIL_2017/CSV_files/siteobs.csv",
    sep = "|", header = T)


nasis_pedon <- pedon |> dplyr::select(peiid, siteobsiidref, earthcovkind1, earthcovkind2, pedlabsampnum) |> dplyr::left_join(siteobs |> dplyr::select(siteobsiid, obsdate), by=c('siteobsiidref'='siteobsiid'))


#join to LT_phy_chem

LT_phy_chem_nasis <- LT_phy_chem |> dplyr::left_join(nasis_pedon, by="peiid") |> dplyr::distinct()
tmap_mode("view")
tmap mode set to interactive viewing
  tm_shape(states) +
    tm_borders() +
    tm_lines(lwd = "strokelwd", legend.lwd.show = FALSE) +
    tm_shape(LT_data_points) +
    tm_dots(col="#1B9E77", size=0.3) +
    
    #tm_scale_bar(position = c(0.06, 0.05)) +
    tm_add_legend('fill', 
    col = c( "#1B9E77"),
    border.col = "grey40",
    size = 1,
    labels = c('KSSL'),
    title="Potential Sampling Areas") +
    tm_layout(main.title = "Loamy Tableland ESD", bg.color = "white", legend.outside = TRUE) +
    tm_view(set.view = c(-99.22, 39.13,  4))
LT_data_points_nlcd_data <- dplyr::bind_cols(LT_phy_chem_nasis, Lt_nlcd.df)

LT_data_points_nlcd <- LT_data_points_nlcd_data |> dplyr::filter(!is.na(texture_lab), !hzn_bot < hzn_top, !hzn_bot == hzn_top)

aqp::depths(LT_data_points_nlcd) <-  pedon_key ~ hzn_top  + hzn_bot 
converting profile IDs from integer to character
LT_data_points_nlcd.slab.r <- aqp::slab(LT_data_points_nlcd, fm = pedon_key ~ clay_total + silt_total + sand_total + bulk_density_third_bar + ph_h2o + organic_carbon_walkley_black + estimated_organic_carbon + aggregate_stability_05_2_mm, slab.structure=c(0,15), slab.fun=mean_na)
Note: aqp::slice() will be deprecated in aqp version 2.0
--> Please consider using the more efficient aqp::dice()
LT_data_points_nlcd.slab.r.1 <- LT_data_points_nlcd.slab.r |> dplyr::select(-c(contributing_fraction)) |> tidyr::pivot_wider(names_from=variable, values_from=value)
LT_data_points_nlcd.slab.r.1[ is.na(LT_data_points_nlcd.slab.r.1) ] <- NA
LT_data_points_nlcd.slab.r.1 <- LT_data_points_nlcd.slab.r.1 |> dplyr::rowwise() |> dplyr::mutate(soc = if_else(!is.na(organic_carbon_walkley_black), organic_carbon_walkley_black, estimated_organic_carbon))|> dplyr::mutate(soc_cl = soc_class(soc), ph_cl = ph_class(ph_h2o), db_cl = db_class(bulk_density_third_bar), txt_class = gettt(sand_total, silt_total, clay_total))


LT_data_points_complete <- LT_data_points_nlcd.slab.r.1 |> dplyr::filter(!is.na(soc_cl) & !is.na(db_cl) & !is.na(ph_cl) & !is.na(txt_class)) |> dplyr::select(pedon_key, top, bottom, soc_cl, ph_cl, db_cl, txt_class) |> dplyr::ungroup() |> dplyr::mutate(pedon_key = as.integer(pedon_key))

LT_data_points_nlcd_data_sub <- LT_data_points_nlcd_data |> dplyr::select(pedon_key, SSL_name, lat, lon, earthcovkind1,obsdate,lc) |> dplyr::distinct()

LT_data_points_complete <- LT_data_points_complete |> dplyr::left_join(LT_data_points_nlcd_data_sub, by="pedon_key")

#DSP4SH database

dsp_data_points_nlcd_data <- dplyr::bind_cols(pedon_lab, dsp_nlcd.df)

aqp::depths(dsp_data_points_nlcd_data) <-  pedon_ID ~ lay_depth_to_top  + lay_depth_to_bottom 
converting profile IDs from integer to character
dsp_data_points_nlcd.slab.r <- aqp::slab(dsp_data_points_nlcd_data, fm = pedon_ID ~ clay_tot_psa + silt_tot_psa + sand_tot_psa + Bulk_Density + ph_h2o + SOC_pct + KSSL_WSA, slab.structure=c(0,15), slab.fun=mean_na)
Note: aqp::slice() will be deprecated in aqp version 2.0
--> Please consider using the more efficient aqp::dice()
Warning: Bad horizonation detected, first matching horizon selected. Use strict=TRUE to enforce QA/QC.Warning: Bad horizonation detected, first matching horizon selected. Use strict=TRUE to enforce QA/QC.Warning: Bad horizonation detected, first matching horizon selected. Use strict=TRUE to enforce QA/QC.Warning: Bad horizonation detected, first matching horizon selected. Use strict=TRUE to enforce QA/QC.Warning: Bad horizonation detected, first matching horizon selected. Use strict=TRUE to enforce QA/QC.Warning: Bad horizonation detected, first matching horizon selected. Use strict=TRUE to enforce QA/QC.Warning: Bad horizonation detected, first matching horizon selected. Use strict=TRUE to enforce QA/QC.Warning: Bad horizonation detected, first matching horizon selected. Use strict=TRUE to enforce QA/QC.Warning: Bad horizonation detected, first matching horizon selected. Use strict=TRUE to enforce QA/QC.Warning: Bad horizonation detected, first matching horizon selected. Use strict=TRUE to enforce QA/QC.Warning: Bad horizonation detected, first matching horizon selected. Use strict=TRUE to enforce QA/QC.Warning: Bad horizonation detected, first matching horizon selected. Use strict=TRUE to enforce QA/QC.Warning: Bad horizonation detected, first matching horizon selected. Use strict=TRUE to enforce QA/QC.Warning: Bad horizonation detected, first matching horizon selected. Use strict=TRUE to enforce QA/QC.Warning: Bad horizonation detected, first matching horizon selected. Use strict=TRUE to enforce QA/QC.
dsp_data_points_nlcd.slab.r.1 <- dsp_data_points_nlcd.slab.r |> dplyr::select(-c(contributing_fraction)) |> tidyr::pivot_wider(names_from=variable, values_from=value)
dsp_data_points_nlcd.slab.r.1[ is.na(dsp_data_points_nlcd.slab.r.1) ] <- NA
dsp_data_points_nlcd.slab.r.1 <- dsp_data_points_nlcd.slab.r.1 |> dplyr::rowwise() |> dplyr::mutate(soc_cl = soc_class(SOC_pct), ph_cl = ph_class(ph_h2o), db_cl = db_class(Bulk_Density), txt_class = gettt(sand_tot_psa, silt_tot_psa, clay_tot_psa))
dsp_data_points_nlcd.slab.r.1 <- dsp_data_points_nlcd.slab.r.1 |> dplyr::ungroup() |> dplyr::rename(pedon_key=pedon_ID)

dsp_data_points_complete <- dsp_data_points_nlcd.slab.r.1 |> dplyr::filter(!is.na(soc_cl) & !is.na(db_cl) & !is.na(ph_cl) & !is.na(txt_class)) |> dplyr::select(pedon_key, top, bottom, soc_cl, ph_cl, db_cl, txt_class) |> dplyr::ungroup() |> dplyr::mutate(pedon_key = as.integer(pedon_key))

dsp_data_points_nlcd <- dplyr::bind_cols(pedon_lab, dsp_nlcd.df)
dsp_data_points_nlcd_data_sub <- dsp_data_points_nlcd |> dplyr::select(pedon_key=pedon_ID, SSL_name=Soil, lat=pedon_y, lon=pedon_x, earthcovkind1=trt,lc) |> dplyr::distinct()
LT_data_points_nlcd_data_sub <- LT_data_points_nlcd_data |> dplyr::select(pedon_key, SSL_name, lat, lon, earthcovkind1,obsdate,lc) |> dplyr::distinct()
dsp_data_points_complete <- dsp_data_points_complete |> dplyr::left_join(dsp_data_points_nlcd_data_sub, by="pedon_key")

combine dataframes

stm_data <- bind_rows(dsp_data_points_complete |> droplevels(), LT_data_points_complete |> dplyr::select(-c(obsdate))|> droplevels())
Error in `bind_rows()`:
! Can't combine `..1$ph_cl` <ordered<10807>> and `..2$ph_cl` <ordered<f70bd>>.
Backtrace:
  1. dplyr::bind_rows(...)
  5. vctrs (local) `<fn>`()
  6. vctrs::vec_default_ptype2(...)
 10. vctrs::stop_incompatible_type(...)
 11. vctrs:::stop_incompatible(...)
 12. vctrs:::stop_vctrs(...)
# Select features
mod <- train(ode_cl_aic_mlr_fs, task = t)
Error in UseMethod("trainLearner") : 
  no applicable method for 'trainLearner' applied to an object of class "c('bnc', 'RLearnerClassif', 'RLearner', 'Learner')"

Pixel /Index Value Description

1 No Change 2 Change from or to Water 3 Change from or to any of the four Urban classes (open space; low, medium, and high intensity) 4 Change from Herbaceous Wetland to Woody Wetland, or vice versa 5 Change from or to Herbaceous Wetland 6 Change from Cultivated Crops to Hay / Pasture, or vice versa 7 Change from or to Cultivated Crops 8 Change from or to Hay / Pasture 9 Persistent Grassland and Shrubland change. This change index attempts to identify changes to persistent Grassland and Shrubland areas, and to separate them from transitional shrubland areas such as regenerating forests. 10 Change from or to Barren 11 Change from or to any of the three Forest classes (Evergreen, Deciduous, and Mixed) 12 Change from or to Woody Wetland

National Land Cover Database Class Legend and Description

Class Value Classification Description

Water

11 Open Water- areas of open water, generally with less than 25% cover of vegetation or soil.

12 Perennial Ice/Snow- areas characterized by a perennial cover of ice and/or snow, generally greater than 25% of total cover.

Developed

21 Developed, Open Space- areas with a mixture of some constructed materials, but mostly vegetation in the form of lawn grasses. Impervious surfaces account for less than 20% of total cover. These areas most commonly include large-lot single-family housing units, parks, golf courses, and vegetation planted in developed settings for recreation, erosion control, or aesthetic purposes.

22 Developed, Low Intensity- areas with a mixture of constructed materials and vegetation. Impervious surfaces account for 20% to 49% percent of total cover. These areas most commonly include single-family housing units.

23 Developed, Medium Intensity -areas with a mixture of constructed materials and vegetation. Impervious surfaces account for 50% to 79% of the total cover. These areas most commonly include single-family housing units.

24 Developed High Intensity-highly developed areas where people reside or work in high numbers. Examples include apartment complexes, row houses and commercial/industrial. Impervious surfaces account for 80% to 100% of the total cover.

Barren

31 Barren Land (Rock/Sand/Clay) - areas of bedrock, desert pavement, scarps, talus, slides, volcanic material, glacial debris, sand dunes, strip mines, gravel pits and other accumulations of earthen material. Generally, vegetation accounts for less than 15% of total cover.

Forest

41 Deciduous Forest- areas dominated by trees generally greater than 5 meters tall, and greater than 20% of total vegetation cover. More than 75% of the tree species shed foliage simultaneously in response to seasonal change.

42 Evergreen Forest- areas dominated by trees generally greater than 5 meters tall, and greater than 20% of total vegetation cover. More than 75% of the tree species maintain their leaves all year. Canopy is never without green foliage.

43 Mixed Forest- areas dominated by trees generally greater than 5 meters tall, and greater than 20% of total vegetation cover. Neither deciduous nor evergreen species are greater than 75% of total tree cover.

Shrubland

51 Dwarf Scrub- Alaska only areas dominated by shrubs less than 20 centimeters tall with shrub canopy typically greater than 20% of total vegetation. This type is often co-associated with grasses, sedges, herbs, and non-vascular vegetation.

52 Shrub/Scrub- areas dominated by shrubs; less than 5 meters tall with shrub canopy typically greater than 20% of total vegetation. This class includes true shrubs, young trees in an early successional stage or trees stunted from environmental conditions.

Herbaceous

71 Grassland/Herbaceous- areas dominated by gramanoid or herbaceous vegetation, generally greater than 80% of total vegetation. These areas are not subject to intensive management such as tilling, but can be utilized for grazing.

72 Sedge/Herbaceous- Alaska only areas dominated by sedges and forbs, generally greater than 80% of total vegetation. This type can occur with significant other grasses or other grass like plants, and includes sedge tundra, and sedge tussock tundra.

73 Lichens- Alaska only areas dominated by fruticose or foliose lichens generally greater than 80% of total vegetation.

74 Moss- Alaska only areas dominated by mosses, generally greater than 80% of total vegetation.

Planted/Cultivated

81 Pasture/Hay-areas of grasses, legumes, or grass-legume mixtures planted for livestock grazing or the production of seed or hay crops, typically on a perennial cycle. Pasture/hay vegetation accounts for greater than 20% of total vegetation.

82 Cultivated Crops -areas used for the production of annual crops, such as corn, soybeans, vegetables, tobacco, and cotton, and also perennial woody crops such as orchards and vineyards. Crop vegetation accounts for greater than 20% of total vegetation. This class also includes all land being actively tilled.

Wetlands

90 Woody Wetlands- areas where forest or shrubland vegetation accounts for greater than 20% of vegetative cover and the soil or substrate is periodically saturated with or covered with water.

Denomination ph range

Ultra acid < 3.5 Extremely acid 3.5–4.4 Very strongly acid 4.5–5.0 Strongly acid 5.1–5.5 Moderately acid 5.6–6.0 Slightly acid 6.1–6.5 Neutral 6.6–7.3 Slightly alkaline 7.4–7.8 Moderately alkaline 7.9–8.4 Strongly alkaline 8.5–9.0 Very strongly alkaline > 9.0

SOC classes (4 classes)

Db classes

ph_class <- function(ph){
if(is.na(ph)){
  class = NA
}else if(ph <= 3.5){
  class = 'Ultra acid'
}else if(ph > 3.5 & ph <= 4.5){
  class = 'Extremely acid'
}else if(ph > 4.5 & ph <= 5){
  class = 'Very strongly acid'
}else if(ph > 5 & ph < 5.6){
  class = 'Strongly acid'
}else if(ph >= 5.6 & ph <= 6){
  class = 'Moderately acid'
}else if(ph > 6 & ph <= 6.5){
  class = 'Slightly acid'
}else if(ph > 6.5 & ph <= 7.3){
  class = 'Neutral'
}else if(ph > 7.3 & ph <= 7.8){
  class = 'Slightly alkaline'
}else if(ph > 7.8 & ph <= 8.4){
  class = 'Moderately alkaline'
}else if(ph > 8.4 & ph <= 9){
  class = 'Strongly alkaline'
}else if(ph > 9 & ph <= 9){
  class = 'Very strongly alkaline'
}else {class = NA}
return(class)
}

soc_class <- function(soc){
if(is.na(soc)){
  class = NA
}else if(soc <= 1){
  class = 'low'
}else if(soc > 1 & soc <= 2){
  class = 'moderate'
}else if(soc > 2 & soc <= 3){
  class = 'high'
}else if(soc > 3){
  class = 'very high'
}else {class = NA}
return(class)
}

db_class <- function(Db){
if(is.na(Db)){
  class = NA
}else if(Db <= 1){
  class = 'very loose'
}else if(Db > 1 & Db <= 1.2){
  class = 'loose'
}else if(Db > 1.2 & Db <= 1.4){
  class = 'normal'
}else if(Db > 1.4 & Db <= 1.6){
  class = 'hard'
}else if(Db > 1.6){
  class = 'compact'
}
return(class)
}

gettt <- function(sand, silt, clay){
  if(is.na(sand) | is.na(silt) | is.na(clay)){
    x = NA
  } else if((silt + 1.5 * clay) < 15){
    x = "Sand"
  } else if((silt + 1.5 * clay) >= 15 & (silt + 2.0 * clay) < 30){
    x = "Loamy sand"
  } else if((clay >= 7) & (clay <= 20) & (sand > 52) & ((silt + 2.0 * clay) >= 30)){
    x = "Sandy loam"
  } else if((clay < 7) & (silt < 50) & ((silt + 2.0 * clay) >= 30)){
    x = "Sandy loam"
  } else if((clay >= 7) & (clay <= 27) & (silt >= 28) & (silt < 50) & (sand <= 52)){
    x = "Loam"
  } else if(((silt >= 50) & (clay >= 12) & (clay < 27)) | ((silt >= 50) & (silt < 80) & (clay < 12))){
    x = "Silt loam"
  } else if((silt >= 80) & (clay < 12)){
    x = "Silt"
  } else if((clay >= 20) & (clay < 35) & (silt < 28) & (sand > 45)){
    x = "Sandy clay loam"
  } else if((clay >= 27) & (clay < 40) & (sand > 20) & (sand <= 45)){
    x = "Clay loam"
  } else if((clay >= 27) & (clay < 40) & (sand <= 20)){
    x = "Silty clay loam"
  } else if((clay >= 35) & (sand >= 45)){
    x = "Sandy clay"
  } else if((clay >= 40) & (silt >= 40)){
    x = "Silty clay"
  } else if((clay >= 40) & (sand <= 45) & (silt < 40)){
    x = "Clay"
  }
  return(x)
}
LS0tCnRpdGxlOiAiUXVhbnQgU1RNIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgpgYGB7cn0KbGlicmFyeShoZXJlKQpsaWJyYXJ5KERCSSkKbGlicmFyeShSU1FMaXRlKQpsaWJyYXJ5KHJhc3RlcikKbGlicmFyeShzZikKbGlicmFyeShodHRyKSAjIGdlbmVyaWMgd2Vic2VydmljZSBwYWNrYWdlCmxpYnJhcnkodG1hcCkKYGBgCgpgYGB7cn0KIyBtZWFuIGZ1bmN0aW9uCm1lYW5fbmEgPC0gZnVuY3Rpb24oeCl7CiAgeF9tZWFuIDwtIG1lYW4oeCwgbmEucm09VFJVRSkKICByZXR1cm4oeF9tZWFuKQp9CgojIGNvbm5lY3QKZGIgPC0gZGJDb25uZWN0KFJTUUxpdGU6OlNRTGl0ZSgpLCAnQzovUl9Ecml2ZS9EYXRhX0ZpbGVzL0xQS1NfRGF0YS9EYXRhL1NvaWxfUGVkb25fRGF0YWJhc2VzL05SQ1MvS1NTTC9MYWJEYXRhTWFydF80LTE3LTIzL25jc3NfbGFiZGF0YS5zcWxpdGUnKQoKZGJMaXN0VGFibGVzKGRiKQoKIyBsaXN0IGZpZWxkcwojIGRiTGlzdEZpZWxkcyhkYiwgJ2xhYl9wZWRvbicpCiMgZGJMaXN0RmllbGRzKGRiLCAnbGFiX3NpdGUnKQojIGRiTGlzdEZpZWxkcyhkYiwgJ2xhYl9waHlzaWNhbF9wcm9wZXJ0aWVzJykKIyBkYkxpc3RGaWVsZHMoZGIsICdsYWJfY2hlbWljYWxfcHJvcGVydGllcycpCiMgZGJMaXN0RmllbGRzKGRiLCAnbGFiX2NvbWJpbmVfbmFzaXNfbmNzcycpCmxhYl9sYXllciA8LSBkYkdldFF1ZXJ5KGRiLCAiU0VMRUNUICogZnJvbSBsYWJfbGF5ZXI7IikKbGFiX3NpdGUgPC0gZGJHZXRRdWVyeShkYiwgIlNFTEVDVCAqIGZyb20gbGFiX3NpdGU7IikKbGFiX3BlZG9uIDwtIGRiR2V0UXVlcnkoZGIsICJTRUxFQ1QgKiBmcm9tIGxhYl9wZWRvbjsiKQpsYWJfcGh5IDwtIGRiR2V0UXVlcnkoZGIsICJTRUxFQ1QgKiBmcm9tIGxhYl9waHlzaWNhbF9wcm9wZXJ0aWVzOyIpCmxhYl9jaGVtIDwtIGRiR2V0UXVlcnkoZGIsICJTRUxFQ1QgKiBmcm9tIGxhYl9jaGVtaWNhbF9wcm9wZXJ0aWVzOyIpCmxhYl9uYXNpcyA8LSBkYkdldFF1ZXJ5KGRiLCAiU0VMRUNUICogZnJvbSBsYWJfY29tYmluZV9uYXNpc19uY3NzOyIpCgojIHNlcmllcyBpbmNsdWRlZCBpbiB0aGUgTG9hbXkgVGFibGVsYW5kIEVTRApMb2FteV90YWJsZWxhbmQgPC0gYygnVWx5c3NlcycsICdSaWNoZmllbGQnLCAnS2VpdGgnLCAnS3VtYScsICdSb3NlYnVkJywgJ0JsYWNrd29vZCcsICdEYXdlcycsICdNYWNlJywgJ01jQ29uYXVnaHknLCAnTm9ya2EnLCAnU2F0YW50YScsICdXZWxkJykKCkxvYW15X3RhYmxlbGFuZF9uYXNpcyA8LSBsYWJfbmFzaXMgfD4gZHBseXI6OmZpbHRlcihTU0xfbmFtZSAlaW4lIExvYW15X3RhYmxlbGFuZCkgfD4gZHBseXI6OnNlbGVjdChwZWRvbl9rZXksIHBlZGxhYnNhbXBudW0sIHBlaWlkLCBzYW1wX25hbWUsY29ycl9uYW1lLCBTU0xfbmFtZSwgbGF0PWxhdGl0dWRlX2RlY2ltYWxfZGVncmVlcywgbG9uPWxvbmdpdHVkZV9kZWNpbWFsX2RlZ3JlZXMpIAoKCnBoeV9sYXllciA8LSBsYWJfcGh5IHw+IGRwbHlyOjpzZWxlY3QobGF5ZXJfa2V5LCB0ZXh0dXJlX2xhYiwgY2xheV90b3RhbCwgc2lsdF90b3RhbCwgc2FuZF90b3RhbCwgYnVsa19kZW5zaXR5X3RoaXJkX2JhciwgYWdncmVnYXRlX3N0YWJpbGl0eV8wNV8yX21tLCB3YXRlcl9yZXRlbnRpb25fdGhpcmRfYmFyLCB3YXRlcl9yZXRlbnRpb25fMTVfYmFyLCB3YXRlcl9yZXRlbnRpb25fZmllbGRfc3RhdGUpIHw+IGRwbHlyOjpsZWZ0X2pvaW4obGFiX2xheWVyIHw+IGRwbHlyOjpzZWxlY3QobGF5ZXJfa2V5LCBsYWJzYW1wbnVtLCBoem5fdG9wLCBoem5fYm90LCBoem5fZGVzZ24sIGh6bl9tYXN0ZXIsIHBlZG9uX2tleSwgc2l0ZV9rZXkpLCBieT0ibGF5ZXJfa2V5IikKCnBoeV9jaGVtX2xheWVyIDwtIHBoeV9sYXllciB8PiBkcGx5cjo6bGVmdF9qb2luKGxhYl9jaGVtIHw+IGRwbHlyOjpzZWxlY3QobGF5ZXJfa2V5LCBwaF9oMm8sdG90YWxfY2FyYm9uX25jcywgdG90YWxfbml0cm9nZW5fbmNzLCBvcmdhbmljX2NhcmJvbl93YWxrbGV5X2JsYWNrLGVzdGltYXRlZF9vcmdhbmljX2NhcmJvbiwgY2FyYm9uX3RvX25pdHJvZ2VuX3JhdGlvKSwgYnk9ImxheWVyX2tleSIpCgoKTFRfcGh5X2NoZW0gPC0gTG9hbXlfdGFibGVsYW5kX25hc2lzIHw+IGRwbHlyOjpsZWZ0X2pvaW4ocGh5X2NoZW1fbGF5ZXIgLCBieT1jKCJwZWRvbl9rZXkiKSkgfD4gZHBseXI6OmZpbHRlcighaXMubmEobGF0KSkKCmBgYAoKYGBge3J9CiNOQVNJUyB0YWJsZXMKIyBwZWRvbiAgdG8gc2l0ZW9iczogc2l0ZW9ic2lpZHJlZj09c2l0ZW9ic2lpZAoKcGVkb24gPC0gZGF0YS50YWJsZTo6ZnJlYWQoIkM6L1JfRHJpdmUvRGF0YV9GaWxlcy9MUEtTX0RhdGEvRGF0YS9Tb2lsX1BlZG9uX0RhdGFiYXNlcy9OUkNTL05BU0lTL05BU0lTX0FQUklMXzIwMTcvQ1NWX2ZpbGVzL3BlZG9uLmNzdiIsCiAgICBzZXAgPSAifCIsIGhlYWRlciA9IFQpCgpzaXRlb2JzIDwtIGRhdGEudGFibGU6OmZyZWFkKCJDOi9SX0RyaXZlL0RhdGFfRmlsZXMvTFBLU19EYXRhL0RhdGEvU29pbF9QZWRvbl9EYXRhYmFzZXMvTlJDUy9OQVNJUy9OQVNJU19BUFJJTF8yMDE3L0NTVl9maWxlcy9zaXRlb2JzLmNzdiIsCiAgICBzZXAgPSAifCIsIGhlYWRlciA9IFQpCgoKbmFzaXNfcGVkb24gPC0gcGVkb24gfD4gZHBseXI6OnNlbGVjdChwZWlpZCwgc2l0ZW9ic2lpZHJlZiwgZWFydGhjb3ZraW5kMSwgZWFydGhjb3ZraW5kMiwgcGVkbGFic2FtcG51bSkgfD4gZHBseXI6OmxlZnRfam9pbihzaXRlb2JzIHw+IGRwbHlyOjpzZWxlY3Qoc2l0ZW9ic2lpZCwgb2JzZGF0ZSksIGJ5PWMoJ3NpdGVvYnNpaWRyZWYnPSdzaXRlb2JzaWlkJykpCgoKI2pvaW4gdG8gTFRfcGh5X2NoZW0KCkxUX3BoeV9jaGVtX25hc2lzIDwtIExUX3BoeV9jaGVtIHw+IGRwbHlyOjpsZWZ0X2pvaW4obmFzaXNfcGVkb24sIGJ5PSJwZWlpZCIpIHw+IGRwbHlyOjpkaXN0aW5jdCgpCmBgYAoKCmBgYHtyfQpMVF9kYXRhX3BvaW50cyA8LSBzdF9hc19zZihMVF9waHlfY2hlbSwgY29vcmRzID0gYygibG9uIiwibGF0IiksIGNycyA9IDQzMjYpCgojIFN0YXRlL01MUkEgQm91bmRhcnkKCiN3ZnNfbWxyYSA8LSAnaHR0cHM6Ly9zZXJ2aWNlcy5hcmNnaXMuY29tL1NYYkRwbWI3eFFrazQ0SlYvQXJjR0lTL3Jlc3Qvc2VydmljZXMvVVNfTUxSQS9GZWF0dXJlU2VydmVyJwp1cmwgPC0gcGFyc2VfdXJsKCJodHRwczovL3NlcnZpY2VzLmFyY2dpcy5jb20vU1hiRHBtYjd4UWtrNDRKVi9hcmNnaXMvcmVzdC9zZXJ2aWNlcyIpCnVybCRwYXRoIDwtIHBhc3RlKHVybCRwYXRoLCAiVVNfTUxSQS9GZWF0dXJlU2VydmVyLzAvcXVlcnkiLCBzZXAgPSAiLyIpCnVybCRxdWVyeSA8LSBsaXN0KHdoZXJlID0gIjE9MSIsCiAgICAgICAgICAgICAgICAgIG91dEZpZWxkcyA9ICIqIiwKICAgICAgICAgICAgICAgICAgcmV0dXJuR2VvbWV0cnkgPSAidHJ1ZSIsCiAgICAgICAgICAgICAgICAgIGYgPSAiZ2VvanNvbiIpCnJlcXVlc3QgPC0gYnVpbGRfdXJsKHVybCkKbWxyYSA8LSBzdF9yZWFkKHJlcXVlc3QpCgojd2ZzX3N0YXRlcyA8LSAnaHR0cHM6Ly9zZXJ2aWNlcy5hcmNnaXMuY29tL1NYYkRwbWI3eFFrazQ0SlYvQXJjR0lTL3Jlc3Qvc2VydmljZXMvVVNBX1N0YXRlc19HZW5lcmFsaXplZC9GZWF0dXJlU2VydmVyJwp1cmwgPC0gcGFyc2VfdXJsKCJodHRwczovL3NlcnZpY2VzLmFyY2dpcy5jb20vU1hiRHBtYjd4UWtrNDRKVi9hcmNnaXMvcmVzdC9zZXJ2aWNlcyIpCnVybCRwYXRoIDwtIHBhc3RlKHVybCRwYXRoLCAiVVNBX1N0YXRlc19HZW5lcmFsaXplZC9GZWF0dXJlU2VydmVyLzAvcXVlcnkiLCBzZXAgPSAiLyIpCnVybCRxdWVyeSA8LSBsaXN0KHdoZXJlID0gIjE9MSIsCiAgICAgICAgICAgICAgICAgIG91dEZpZWxkcyA9ICIqIiwKICAgICAgICAgICAgICAgICAgcmV0dXJuR2VvbWV0cnkgPSAidHJ1ZSIsCiAgICAgICAgICAgICAgICAgIGYgPSAiZ2VvanNvbiIpCnJlcXVlc3QgPC0gYnVpbGRfdXJsKHVybCkKc3RhdGVzIDwtIHN0X3JlYWQocmVxdWVzdCkKc3RhdGVzIDwtIHN0X2Nyb3Aoc3RhdGVzLCBtbHJhKQoKCnRtYXBfbW9kZSgidmlldyIpCiAgdG1fc2hhcGUoc3RhdGVzKSArCiAgICB0bV9ib3JkZXJzKCkgKwogICAgdG1fbGluZXMobHdkID0gInN0cm9rZWx3ZCIsIGxlZ2VuZC5sd2Quc2hvdyA9IEZBTFNFKSArCiAgICB0bV9zaGFwZShMVF9kYXRhX3BvaW50cykgKwogICAgdG1fZG90cyhjb2w9IiMxQjlFNzciLCBzaXplPTAuMykgKwogICAgCiAgICAjdG1fc2NhbGVfYmFyKHBvc2l0aW9uID0gYygwLjA2LCAwLjA1KSkgKwogICAgdG1fYWRkX2xlZ2VuZCgnZmlsbCcsIAoJY29sID0gYyggIiMxQjlFNzciKSwKCWJvcmRlci5jb2wgPSAiZ3JleTQwIiwKCXNpemUgPSAxLAoJbGFiZWxzID0gYygnS1NTTCcpLAoJdGl0bGU9IlBvdGVudGlhbCBTYW1wbGluZyBBcmVhcyIpICsKICAgIHRtX2xheW91dChtYWluLnRpdGxlID0gIkxvYW15IFRhYmxlbGFuZCBFU0QiLCBiZy5jb2xvciA9ICJ3aGl0ZSIsIGxlZ2VuZC5vdXRzaWRlID0gVFJVRSkgKwogICAgdG1fdmlldyhzZXQudmlldyA9IGMoLTk5LjIyLCAzOS4xMywgIDQpKQoKYGBgCgpgYGB7cn0KbGlicmFyeShyYXN0ZXIpCgoKbmxjZF9jaGFuZ2UgPC0gcmFzdGVyOjpyYXN0ZXIoJ0M6L1JfRHJpdmUvRGF0YV9GaWxlcy9OUkNTL05MQ0RfRVNEL05MQ0RfMjAwMV8yMDE5X2NoYW5nZV9pbmRleF9MNDhfMjAyMTA2MDRfOVpkaWJwaGhzclBUeGRnWktPanAudGlmZicpCkx0X25sY2RfY2hhbmdlIDwtIHJhc3Rlcjo6ZXh0cmFjdChubGNkX2NoYW5nZSwgTFRfZGF0YV9wb2ludHMpCgpubGNkMDEgPC0gcmFzdGVyOjpyYXN0ZXIoJ0M6L1JfRHJpdmUvRGF0YV9GaWxlcy9OUkNTL05MQ0RfRVNEL05MQ0RfMjAwMV9MYW5kX0NvdmVyX0w0OF8yMDIxMDYwNF85WmRpYnBoaHNyUFR4ZGdaS09qcC50aWZmJykKbmxjZDA0IDwtIHJhc3Rlcjo6cmFzdGVyKCdDOi9SX0RyaXZlL0RhdGFfRmlsZXMvTlJDUy9OTENEX0VTRC9OTENEXzIwMDRfTGFuZF9Db3Zlcl9MNDhfMjAyMTA2MDRfOVpkaWJwaGhzclBUeGRnWktPanAudGlmZicpCm5sY2QwNiA8LSByYXN0ZXI6OnJhc3RlcignQzovUl9Ecml2ZS9EYXRhX0ZpbGVzL05SQ1MvTkxDRF9FU0QvTkxDRF8yMDA2X0xhbmRfQ292ZXJfTDQ4XzIwMjEwNjA0XzlaZGlicGhoc3JQVHhkZ1pLT2pwLnRpZmYnKQpubGNkMDggPC0gcmFzdGVyOjpyYXN0ZXIoJ0M6L1JfRHJpdmUvRGF0YV9GaWxlcy9OUkNTL05MQ0RfRVNEL05MQ0RfMjAwOF9MYW5kX0NvdmVyX0w0OF8yMDIxMDYwNF85WmRpYnBoaHNyUFR4ZGdaS09qcC50aWZmJykKbmxjZDExIDwtIHJhc3Rlcjo6cmFzdGVyKCdDOi9SX0RyaXZlL0RhdGFfRmlsZXMvTlJDUy9OTENEX0VTRC9OTENEXzIwMTFfTGFuZF9Db3Zlcl9MNDhfMjAyMTA2MDRfOVpkaWJwaGhzclBUeGRnWktPanAudGlmZicpCm5sY2QxMyA8LSByYXN0ZXI6OnJhc3RlcignQzovUl9Ecml2ZS9EYXRhX0ZpbGVzL05SQ1MvTkxDRF9FU0QvTkxDRF8yMDEzX0xhbmRfQ292ZXJfTDQ4XzIwMjEwNjA0XzlaZGlicGhoc3JQVHhkZ1pLT2pwLnRpZmYnKQpubGNkMTYgPC0gcmFzdGVyOjpyYXN0ZXIoJ0M6L1JfRHJpdmUvRGF0YV9GaWxlcy9OUkNTL05MQ0RfRVNEL05MQ0RfMjAxNl9MYW5kX0NvdmVyX0w0OF8yMDIxMDYwNF85WmRpYnBoaHNyUFR4ZGdaS09qcC50aWZmJykKbmxjZDE5IDwtIHJhc3Rlcjo6cmFzdGVyKCdDOi9SX0RyaXZlL0RhdGFfRmlsZXMvTlJDUy9OTENEX0VTRC9OTENEXzIwMTlfTGFuZF9Db3Zlcl9MNDhfMjAyMTA2MDRfOVpkaWJwaGhzclBUeGRnWktPanAudGlmZicpCkx0X25sY2RfMDEgPC0gcmFzdGVyOjpleHRyYWN0KG5sY2QwMSwgTFRfZGF0YV9wb2ludHMpCkx0X25sY2RfMDQgPC0gcmFzdGVyOjpleHRyYWN0KG5sY2QwNCwgTFRfZGF0YV9wb2ludHMpCkx0X25sY2RfMDYgPC0gcmFzdGVyOjpleHRyYWN0KG5sY2QwNiwgTFRfZGF0YV9wb2ludHMpCkx0X25sY2RfMDggPC0gcmFzdGVyOjpleHRyYWN0KG5sY2QwOCwgTFRfZGF0YV9wb2ludHMpCkx0X25sY2RfMTEgPC0gcmFzdGVyOjpleHRyYWN0KG5sY2QxMSwgTFRfZGF0YV9wb2ludHMpCkx0X25sY2RfMTMgPC0gcmFzdGVyOjpleHRyYWN0KG5sY2QxMywgTFRfZGF0YV9wb2ludHMpCkx0X25sY2RfMTYgPC0gcmFzdGVyOjpleHRyYWN0KG5sY2QxNiwgTFRfZGF0YV9wb2ludHMpCkx0X25sY2RfMTkgPC0gcmFzdGVyOjpleHRyYWN0KG5sY2QxOSwgTFRfZGF0YV9wb2ludHMpCgpMdF9ubGNkLmRmIDwtIGRhdGEuZnJhbWUoTHRfbmxjZF9jaGFuZ2UsIEx0X25sY2RfMDEsIEx0X25sY2RfMDQsIEx0X25sY2RfMDYsIEx0X25sY2RfMDgsIEx0X25sY2RfMTEsIEx0X25sY2RfMTMsIEx0X25sY2RfMTYsIEx0X25sY2RfMTkpIHw+IHB1cnJyOjpzZXRfbmFtZXMoJ25sY2RfY2hhbmdlJywgJ25sY2QwMScsICdubGNkMDQnLCAnbmxjZDA2JywgJ25sY2QwOCcsICdubGNkMTEnLCAnbmxjZDEzJywgJ25sY2QxNicsICdubGNkMTknLCApCkx0X25sY2QuZGYgPC0gTHRfbmxjZC5kZiB8PiBkcGx5cjo6bXV0YXRlKGxjID0gZHBseXI6OmNhc2Vfd2hlbihubGNkX2NoYW5nZT09MSAmIG5sY2QxOT09ODIgfiAnQ3JvcHMnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBubGNkX2NoYW5nZT09MSAmIG5sY2QxOT09ODEgfiAnUGFzdHVyZScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5sY2RfY2hhbmdlPT0xICYgbmxjZDE5PT03MSB+ICdHcmFzc2xhbmQnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBubGNkX2NoYW5nZT09NyAmIG5sY2QwNj09NTIgfiAnU2hydWItQ3JvcDA3JywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmxjZF9jaGFuZ2U9PTcgJiBubGNkMDg9PTcxIH4gJ0dyYXNzbGFuZC1Dcm9wMDknLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBubGNkX2NoYW5nZT09NyAmIG5sY2QwNj09NzEgJiBubGNkMDg9PTgyIH4gJ0dyYXNzbGFuZC1Dcm9wMDcnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gJ0ZhaWwnKSkKCkxUX2RhdGFfcG9pbnRzX25sY2RfZGF0YSA8LSBkcGx5cjo6YmluZF9jb2xzKExUX3BoeV9jaGVtX25hc2lzLCBMdF9ubGNkLmRmKQoKTFRfZGF0YV9wb2ludHNfbmxjZCA8LSBMVF9kYXRhX3BvaW50c19ubGNkX2RhdGEgfD4gZHBseXI6OmZpbHRlcighaXMubmEodGV4dHVyZV9sYWIpLCAhaHpuX2JvdCA8IGh6bl90b3AsICFoem5fYm90ID09IGh6bl90b3ApCgphcXA6OmRlcHRocyhMVF9kYXRhX3BvaW50c19ubGNkKSA8LSAgcGVkb25fa2V5IH4gaHpuX3RvcCAgKyBoem5fYm90IApMVF9kYXRhX3BvaW50c19ubGNkLnNsYWIuciA8LSBhcXA6OnNsYWIoTFRfZGF0YV9wb2ludHNfbmxjZCwgZm0gPSBwZWRvbl9rZXkgfiBjbGF5X3RvdGFsICsgc2lsdF90b3RhbCArIHNhbmRfdG90YWwgKyBidWxrX2RlbnNpdHlfdGhpcmRfYmFyICsgcGhfaDJvICsgb3JnYW5pY19jYXJib25fd2Fsa2xleV9ibGFjayArIGVzdGltYXRlZF9vcmdhbmljX2NhcmJvbiArIGFnZ3JlZ2F0ZV9zdGFiaWxpdHlfMDVfMl9tbSwgc2xhYi5zdHJ1Y3R1cmU9YygwLDE1KSwgc2xhYi5mdW49bWVhbl9uYSkKTFRfZGF0YV9wb2ludHNfbmxjZC5zbGFiLnIuMSA8LSBMVF9kYXRhX3BvaW50c19ubGNkLnNsYWIuciB8PiBkcGx5cjo6c2VsZWN0KC1jKGNvbnRyaWJ1dGluZ19mcmFjdGlvbikpIHw+IHRpZHlyOjpwaXZvdF93aWRlcihuYW1lc19mcm9tPXZhcmlhYmxlLCB2YWx1ZXNfZnJvbT12YWx1ZSkKTFRfZGF0YV9wb2ludHNfbmxjZC5zbGFiLnIuMVsgaXMubmEoTFRfZGF0YV9wb2ludHNfbmxjZC5zbGFiLnIuMSkgXSA8LSBOQQpMVF9kYXRhX3BvaW50c19ubGNkLnNsYWIuci4xIDwtIExUX2RhdGFfcG9pbnRzX25sY2Quc2xhYi5yLjEgfD4gZHBseXI6OnJvd3dpc2UoKSB8PiBkcGx5cjo6bXV0YXRlKHNvYyA9IGlmX2Vsc2UoIWlzLm5hKG9yZ2FuaWNfY2FyYm9uX3dhbGtsZXlfYmxhY2spLCBvcmdhbmljX2NhcmJvbl93YWxrbGV5X2JsYWNrLCBlc3RpbWF0ZWRfb3JnYW5pY19jYXJib24pKXw+IGRwbHlyOjptdXRhdGUoc29jX2NsID0gc29jX2NsYXNzKHNvYyksIHBoX2NsID0gcGhfY2xhc3MocGhfaDJvKSwgZGJfY2wgPSBkYl9jbGFzcyhidWxrX2RlbnNpdHlfdGhpcmRfYmFyKSwgdHh0X2NsYXNzID0gZ2V0dHQoc2FuZF90b3RhbCwgc2lsdF90b3RhbCwgY2xheV90b3RhbCkpCgoKTFRfZGF0YV9wb2ludHNfY29tcGxldGUgPC0gTFRfZGF0YV9wb2ludHNfbmxjZC5zbGFiLnIuMSB8PiBkcGx5cjo6ZmlsdGVyKCFpcy5uYShzb2NfY2wpICYgIWlzLm5hKGRiX2NsKSAmICFpcy5uYShwaF9jbCkgJiAhaXMubmEodHh0X2NsYXNzKSkgfD4gZHBseXI6OnNlbGVjdChwZWRvbl9rZXksIHRvcCwgYm90dG9tLCBzb2NfY2wsIHBoX2NsLCBkYl9jbCwgdHh0X2NsYXNzKSB8PiBkcGx5cjo6dW5ncm91cCgpIHw+IGRwbHlyOjptdXRhdGUocGVkb25fa2V5ID0gYXMuaW50ZWdlcihwZWRvbl9rZXkpKQoKTFRfZGF0YV9wb2ludHNfbmxjZF9kYXRhX3N1YiA8LSBMVF9kYXRhX3BvaW50c19ubGNkX2RhdGEgfD4gZHBseXI6OnNlbGVjdChwZWRvbl9rZXksIFNTTF9uYW1lLCBsYXQsIGxvbiwgZWFydGhjb3ZraW5kMSxvYnNkYXRlLGxjKSB8PiBkcGx5cjo6ZGlzdGluY3QoKQoKTFRfZGF0YV9wb2ludHNfY29tcGxldGUgPC0gTFRfZGF0YV9wb2ludHNfY29tcGxldGUgfD4gZHBseXI6OmxlZnRfam9pbihMVF9kYXRhX3BvaW50c19ubGNkX2RhdGFfc3ViLCBieT0icGVkb25fa2V5IikKYGBgCgojRFNQNFNIIGRhdGFiYXNlCmBgYHtyfQpsaWJyYXJ5KERCSSkKbGlicmFyeShSU1FMaXRlKQpsaWJyYXJ5KGRwbHlyLCB3YXJuLmNvbmZsaWN0cyA9IEZBTFNFKQpsaWJyYXJ5KHJlYWR4bCkKbGlicmFyeShyZWFkcikKbGlicmFyeShoZXJlKQoKZHNwNHNoNCA8LSBkYkNvbm5lY3QoU1FMaXRlKCksIGhlcmUoImRhdGEvcmF3X2RhdGEvZHNwNHNoNC5kYiIpKQpkYkxpc3RUYWJsZXMoZHNwNHNoNCkgI1RvIGNoZWNrIHRhYmxlcwoKcGVkb24gPC0gZGJHZXRRdWVyeShkc3A0c2g0LCAiU0VMRUNUICogZnJvbSBwZWRvbjsiKQpjb29wX2xhYiA8LSBkYkdldFF1ZXJ5KGRzcDRzaDQsICJTRUxFQ1QgKiBmcm9tIGNvb3BsYWJtc3Q7IikKa3NzbF9sYWIgPC0gZGJHZXRRdWVyeShkc3A0c2g0LCAiU0VMRUNUICogZnJvbSBrc3NsbGFibXN0OyIpCmxheWVyZGVzYyA8LSBkYkdldFF1ZXJ5KGRzcDRzaDQsICJTRUxFQ1QgKiBmcm9tIGxheWVyZGVzY3JpcHRpb247IikKbGF5ZXJkZXNnIDwtIGRiR2V0UXVlcnkoZHNwNHNoNCwgIlNFTEVDVCAqIGZyb20gbGF5ZXJkZXNpZ25hdGlvbjsiKQpwbG90IDwtIGRiR2V0UXVlcnkoZHNwNHNoNCwgIlNFTEVDVCAqIGZyb20gcGxvdG92ZXJ2aWV3OyIpCmRzcHBsb3RtZ3QgPC0gZGJHZXRRdWVyeShkc3A0c2g0LCAiU0VMRUNUICogZnJvbSBkc3BwbG90bWd0OyIpCgpsYWIgPC0gY29vcF9sYWIgfD4gZHBseXI6OnNlbGVjdCgtYyhEU1BfUGVkb24pKSB8PiBkcGx5cjo6bGVmdF9qb2luKGtzc2xfbGFiLCBieT1jKCdLU1NMX2xhYnNhbXBudW0nPSduYXR1cmFsX2tleScpKQpwZWRvbl9sYWIgPC0gcGVkb24gfD4gZHBseXI6OmxlZnRfam9pbihsYWIsIGJ5PSdEU1BfUGVkb25fSUQnKQpwZWRvbl9sYWIgPC0gcGVkb25fbGFiIHw+IGRwbHlyOjpsZWZ0X2pvaW4oZHNwcGxvdG1ndCB8PiBkcGx5cjo6c2VsZWN0KC1jKFNvaWwpKSwgYnk9J0RTUF9QbG90X0lEJykKcGVkb25fbGFiIDwtIHBlZG9uX2xhYiB8PiBkcGx5cjo6bGVmdF9qb2luKGxheWVyZGVzYyB8PiBkcGx5cjo6cmVuYW1lKGZpZWxkX2NsYXlfcGN0ID0gQ2xheV9wY3QpLCBieT1jKCdEU1BfUGVkb25fSUQnPSdEU1BfUGVkb25fSUQnLCAnRFNQX3NhbXBsZV9JRCc9J0RTUF9zYW1wbGVfSUQnKSkKcGVkb25fbGFiIDwtIHBlZG9uX2xhYiB8PiBkcGx5cjo6bGVmdF9qb2luKGxheWVyZGVzZywgYnk9YygnRFNQX1BlZG9uX0lEJz0nRFNQX1BlZG9uX0lEJywgJ0RTUF9zYW1wbGVfSUQnPSdEU1Bfc2FtcGxlX0lEJykpCnBlZG9uX2xhYiA8LSBwZWRvbl9sYWIgfD4gZHBseXI6OmZpbHRlcihTb2lsPT0iS2VpdGgiKQoKcGVkb25fbGFiIDwtIHBlZG9uX2xhYiB8PiBkcGx5cjo6c2VsZWN0KGMocGVkb25fSUQsRFNQX1BlZG9uX0lELERTUF9QbG90X0lELERTUF9zYW1wbGVfSUQsTFUsdGlsbCx0cnQsIHBlZG9uX3gscGVkb25feSxTb2lsLEJ1bGtfRGVuc2l0eSxXYXRlcl9Db250ZW50LFNPQ19wY3QsS1NTTF9XU0EsWW9kZXJfQWdnU3RhYl9NV0QsU29pbF9SZXNwaXJhdGlvbixCZ2x1Y29zaWRhc2UsQmdsdWNvc2FtaW5pZGFzZSxBbGthbGluZVBob3NwaGF0YXNlLEFjaWRQaG9zcGhhdGFzZSxQaG9zcGhvZGllc3RlcmFzZSxQT1hfQyxBQ0UsS1NTTF9sYWJzYW1wbnVtLGhvcml6b25fZGVzaWduYXRpb24sbGF5X2RlcHRoX3RvX3RvcCwgbGF5X2RlcHRoX3RvX2JvdHRvbSxjbGF5X3RvdF9wc2Esc2lsdF90b3RfcHNhLHNhbmRfdG90X3BzYSxjbzNfY2x5LHRleF9wc2RhLGFkb2QsY2FjbzMscGhfY2FjbDIscGhfaDJvLENLTW5PNCxQTml0cm9CR2x1LGFnX3N0YWIsY190b3RfbmNzLG5fdG90X25jcyxzX3RvdF9uY3MsZXN0aW1hdGVkX29yZ2FuaWNfQyxGaWVsZF9UZXh0dXJlLENvYXJzZV9GcmFnX3ZvbHVtZSxmaWVsZF9jbGF5X3BjdCxDb2xvcl9Nb2lzdF9IdWUsQ29sb3JfTW9pc3RfVmFsdWUsQ29sb3JfTW9pc3RfQ2hyb21hKSkKCgpwZWRvbl9sYWJfcG9pbnRzIDwtIHN0X2FzX3NmKHBlZG9uX2xhYiwgY29vcmRzID0gYygicGVkb25feCIsInBlZG9uX3kiKSwgY3JzID0gNDMyNikKCmRzcF9ubGNkX2NoYW5nZSA8LSByYXN0ZXI6OmV4dHJhY3QobmxjZF9jaGFuZ2UsIHBlZG9uX2xhYl9wb2ludHMpCmRzcF9ubGNkXzAxIDwtIHJhc3Rlcjo6ZXh0cmFjdChubGNkMDEsIHBlZG9uX2xhYl9wb2ludHMpCmRzcF9ubGNkXzA0IDwtIHJhc3Rlcjo6ZXh0cmFjdChubGNkMDQsIHBlZG9uX2xhYl9wb2ludHMpCmRzcF9ubGNkXzA2IDwtIHJhc3Rlcjo6ZXh0cmFjdChubGNkMDYsIHBlZG9uX2xhYl9wb2ludHMpCmRzcF9ubGNkXzA4IDwtIHJhc3Rlcjo6ZXh0cmFjdChubGNkMDgsIHBlZG9uX2xhYl9wb2ludHMpCmRzcF9ubGNkXzExIDwtIHJhc3Rlcjo6ZXh0cmFjdChubGNkMTEsIHBlZG9uX2xhYl9wb2ludHMpCmRzcF9ubGNkXzEzIDwtIHJhc3Rlcjo6ZXh0cmFjdChubGNkMTMsIHBlZG9uX2xhYl9wb2ludHMpCmRzcF9ubGNkXzE2IDwtIHJhc3Rlcjo6ZXh0cmFjdChubGNkMTYsIHBlZG9uX2xhYl9wb2ludHMpCmRzcF9ubGNkXzE5IDwtIHJhc3Rlcjo6ZXh0cmFjdChubGNkMTksIHBlZG9uX2xhYl9wb2ludHMpCgpkc3BfbmxjZC5kZiA8LSBkYXRhLmZyYW1lKGRzcF9ubGNkX2NoYW5nZSwgZHNwX25sY2RfMDEsIGRzcF9ubGNkXzA0LCBkc3BfbmxjZF8wNiwgZHNwX25sY2RfMDgsIGRzcF9ubGNkXzExLCBkc3BfbmxjZF8xMywgZHNwX25sY2RfMTYsIGRzcF9ubGNkXzE5KSB8PiBwdXJycjo6c2V0X25hbWVzKCdubGNkX2NoYW5nZScsICdubGNkMDEnLCAnbmxjZDA0JywgJ25sY2QwNicsICdubGNkMDgnLCAnbmxjZDExJywgJ25sY2QxMycsICdubGNkMTYnLCAnbmxjZDE5JywgKQpkc3BfbmxjZC5kZiA8LSBkc3BfbmxjZC5kZiB8PiBkcGx5cjo6bXV0YXRlKGxjID0gZHBseXI6OmNhc2Vfd2hlbihubGNkX2NoYW5nZT09MSAmIG5sY2QxOT09ODIgfiAnQ3JvcHMnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBubGNkX2NoYW5nZT09MSAmIG5sY2QxOT09ODEgfiAnUGFzdHVyZScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5sY2RfY2hhbmdlPT0xICYgbmxjZDE5PT03MSB+ICdHcmFzc2xhbmQnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBubGNkX2NoYW5nZT09NyAmIG5sY2QwNj09NTIgfiAnU2hydWItQ3JvcDA3JywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmxjZF9jaGFuZ2U9PTcgJiBubGNkMDg9PTcxIH4gJ0dyYXNzbGFuZC1Dcm9wMDknLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBubGNkX2NoYW5nZT09NyAmIG5sY2QwNj09NzEgJiBubGNkMDg9PTgyIH4gJ0dyYXNzbGFuZC1Dcm9wMDcnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gJ0ZhaWwnKSkKCmRzcF9kYXRhX3BvaW50c19ubGNkX2RhdGEgPC0gZHBseXI6OmJpbmRfY29scyhwZWRvbl9sYWIsIGRzcF9ubGNkLmRmKQoKYXFwOjpkZXB0aHMoZHNwX2RhdGFfcG9pbnRzX25sY2RfZGF0YSkgPC0gIHBlZG9uX0lEIH4gbGF5X2RlcHRoX3RvX3RvcCAgKyBsYXlfZGVwdGhfdG9fYm90dG9tIApkc3BfZGF0YV9wb2ludHNfbmxjZC5zbGFiLnIgPC0gYXFwOjpzbGFiKGRzcF9kYXRhX3BvaW50c19ubGNkX2RhdGEsIGZtID0gcGVkb25fSUQgfiBjbGF5X3RvdF9wc2EgKyBzaWx0X3RvdF9wc2EgKyBzYW5kX3RvdF9wc2EgKyBCdWxrX0RlbnNpdHkgKyBwaF9oMm8gKyBTT0NfcGN0ICsgS1NTTF9XU0EsIHNsYWIuc3RydWN0dXJlPWMoMCwxNSksIHNsYWIuZnVuPW1lYW5fbmEpCmRzcF9kYXRhX3BvaW50c19ubGNkLnNsYWIuci4xIDwtIGRzcF9kYXRhX3BvaW50c19ubGNkLnNsYWIuciB8PiBkcGx5cjo6c2VsZWN0KC1jKGNvbnRyaWJ1dGluZ19mcmFjdGlvbikpIHw+IHRpZHlyOjpwaXZvdF93aWRlcihuYW1lc19mcm9tPXZhcmlhYmxlLCB2YWx1ZXNfZnJvbT12YWx1ZSkKZHNwX2RhdGFfcG9pbnRzX25sY2Quc2xhYi5yLjFbIGlzLm5hKGRzcF9kYXRhX3BvaW50c19ubGNkLnNsYWIuci4xKSBdIDwtIE5BCmRzcF9kYXRhX3BvaW50c19ubGNkLnNsYWIuci4xIDwtIGRzcF9kYXRhX3BvaW50c19ubGNkLnNsYWIuci4xIHw+IGRwbHlyOjpyb3d3aXNlKCkgfD4gZHBseXI6Om11dGF0ZShzb2NfY2wgPSBzb2NfY2xhc3MoU09DX3BjdCksIHBoX2NsID0gcGhfY2xhc3MocGhfaDJvKSwgZGJfY2wgPSBkYl9jbGFzcyhCdWxrX0RlbnNpdHkpLCB0eHRfY2xhc3MgPSBnZXR0dChzYW5kX3RvdF9wc2EsIHNpbHRfdG90X3BzYSwgY2xheV90b3RfcHNhKSkKZHNwX2RhdGFfcG9pbnRzX25sY2Quc2xhYi5yLjEgPC0gZHNwX2RhdGFfcG9pbnRzX25sY2Quc2xhYi5yLjEgfD4gZHBseXI6OnVuZ3JvdXAoKSB8PiBkcGx5cjo6cmVuYW1lKHBlZG9uX2tleT1wZWRvbl9JRCkKCmRzcF9kYXRhX3BvaW50c19jb21wbGV0ZSA8LSBkc3BfZGF0YV9wb2ludHNfbmxjZC5zbGFiLnIuMSB8PiBkcGx5cjo6ZmlsdGVyKCFpcy5uYShzb2NfY2wpICYgIWlzLm5hKGRiX2NsKSAmICFpcy5uYShwaF9jbCkgJiAhaXMubmEodHh0X2NsYXNzKSkgfD4gZHBseXI6OnNlbGVjdChwZWRvbl9rZXksIHRvcCwgYm90dG9tLCBzb2NfY2wsIHBoX2NsLCBkYl9jbCwgdHh0X2NsYXNzKSB8PiBkcGx5cjo6dW5ncm91cCgpIHw+IGRwbHlyOjptdXRhdGUocGVkb25fa2V5ID0gYXMuaW50ZWdlcihwZWRvbl9rZXkpKQoKZHNwX2RhdGFfcG9pbnRzX25sY2QgPC0gZHBseXI6OmJpbmRfY29scyhwZWRvbl9sYWIsIGRzcF9ubGNkLmRmKQpkc3BfZGF0YV9wb2ludHNfbmxjZF9kYXRhX3N1YiA8LSBkc3BfZGF0YV9wb2ludHNfbmxjZCB8PiBkcGx5cjo6c2VsZWN0KHBlZG9uX2tleT1wZWRvbl9JRCwgU1NMX25hbWU9U29pbCwgbGF0PXBlZG9uX3ksIGxvbj1wZWRvbl94LCBlYXJ0aGNvdmtpbmQxPXRydCxsYykgfD4gZHBseXI6OmRpc3RpbmN0KCkKTFRfZGF0YV9wb2ludHNfbmxjZF9kYXRhX3N1YiA8LSBMVF9kYXRhX3BvaW50c19ubGNkX2RhdGEgfD4gZHBseXI6OnNlbGVjdChwZWRvbl9rZXksIFNTTF9uYW1lLCBsYXQsIGxvbiwgZWFydGhjb3ZraW5kMSxvYnNkYXRlLGxjKSB8PiBkcGx5cjo6ZGlzdGluY3QoKQpkc3BfZGF0YV9wb2ludHNfY29tcGxldGUgPC0gZHNwX2RhdGFfcG9pbnRzX2NvbXBsZXRlIHw+IGRwbHlyOjpsZWZ0X2pvaW4oZHNwX2RhdGFfcG9pbnRzX25sY2RfZGF0YV9zdWIsIGJ5PSJwZWRvbl9rZXkiKQoKYGBgCgojIGNvbWJpbmUgZGF0YWZyYW1lcwpgYGB7cn0Kc3RtX2RhdGEgPC0gYmluZF9yb3dzKGRzcF9kYXRhX3BvaW50c19jb21wbGV0ZSwgTFRfZGF0YV9wb2ludHNfY29tcGxldGUgfD4gZHBseXI6OnNlbGVjdCgtYyhvYnNkYXRlKSkpCgpzdG1fZGF0YSA8LSBzdG1fZGF0YSB8PiBkcGx5cjo6bXV0YXRlKHNvY19jbCA9IGZhY3Rvcihzb2NfY2wsIG9yZGVyPVRSVUUsIGxldmVscz1jKCdsb3cnLCAnbW9kZXJhdGUnLCAnaGlnaCcsICd2ZXJ5IGhpZ2gnKSksIGRiX2NsID0gZmFjdG9yKGRiX2NsLCBvcmRlcj1UUlVFLCBsZXZlbHM9YygndmVyeSBsb29zZScsICdsb29zZScsICdub3JtYWwnLCAnaGFyZCcsICdjb21wYWN0JykpLCBwaF9jbCA9IGZhY3RvcihwaF9jbCwgb3JkZXI9VFJVRSwgbGV2ZWxzPWMoIlN0cm9uZ2x5IGFjaWQiLCAiTW9kZXJhdGVseSBhY2lkIiwgIlNsaWdodGx5IGFjaWQiLCAiTmV1dHJhbCIsICJTbGlnaHRseSBhbGthbGluZSIsICJNb2RlcmF0ZWx5IGFsa2FsaW5lIikpLCB0eHRfY2xhc3MgPSBmYWN0b3IodHh0X2NsYXNzLCBvcmRlcj1UUlVFLCBsZXZlbHM9dGV4dHVyZXMpKSAKCnN0bV9kYXRhIDwtIHN0bV9kYXRhIHw+IGRwbHlyOjptdXRhdGUobGM9IGlmX2Vsc2UobGM9PSJGYWlsIiwgIkdyYXNzbGFuZCIsIGxjKSkKCgpgYGAKCmBgYHtyfQoKbGlicmFyeShibmNsYXNzaWZ5KQpzdG1fZGF0YV9zdWIgPC0gc3RtX2RhdGEgfD4gZHBseXI6OmZpbHRlcihsYz09IkNyb3BzIiB8IGxjPT0iR3Jhc3NsYW5kIikgfD4gZHBseXI6OnNlbGVjdChsYywgdHh0X2NsYXNzLCBkYl9jbCwgcGhfY2wsIHNvY19jbCkgfD4gZHBseXI6Om11dGF0ZShsYz1mYWN0b3IobGMpKSB8PiBhcy5kYXRhLmZyYW1lKCkKc3RtX2RhdGFfc3ViIDwtIHN0bV9kYXRhIHw+IGRwbHlyOjpzZWxlY3QobGMsIHR4dF9jbGFzcywgZGJfY2wsIHBoX2NsLCBzb2NfY2wpIHw+IGRwbHlyOjptdXRhdGUobGM9ZmFjdG9yKGxjKSkKCnN0bV9kYXRhX3N1YiA8LSBzdG1fZGF0YV9zdWIgfD4gZHBseXI6Om11dGF0ZSh0eHRfY2xhc3MgPSBmYWN0b3IodHh0X2NsYXNzLCBvcmRlcj1GKSwgcGhfY2wgPSBmYWN0b3IocGhfY2wsIG9yZGVyPUYpLCBzb2NfY2wgPSBmYWN0b3Ioc29jX2NsLCBvcmRlcj1GKSwgZGJfY2wgPSBmYWN0b3IoZGJfY2wsIG9yZGVyPUYpKSB8PiBhcy5kYXRhLmZyYW1lKCkKCm5iIDwtIG5iKCdsYycsIHN0bV9kYXRhX3N1YikgIyBMZWFybiBhIG5haXZlIEJheWVzIHN0cnVjdHVyZQpuYiA8LSBscChuYiwgc3RtX2RhdGFfc3ViLCBzbW9vdGggPSAxKSAjIExlYXJuIHBhcmFtZXRlcnMKCmN2KG5iLCBzdG1fZGF0YV9zdWIsIGsgPSAxMCkgIyAxMC1mb2xkIENyb3NzLXZhbGlkYXRpb24gZXN0aW1hdGUgb2YgYWNjdXJhY3kKIz4gWzFdIDAuODU3NjA0NQpoZWFkKHByZWRpY3QobmIsIHN0bV9kYXRhX3N1YikpICMgQ2xhc3NpZnkgdGhlIGVudGlyZSBkYXRhIHNldAojPiBbMV0gdW5hY2MgdW5hY2MgdW5hY2MgdW5hY2MgdW5hY2MgdW5hY2MKIz4gTGV2ZWxzOiB1bmFjYyBhY2MgZ29vZCB2Z29vZAojPiAKIz4gIyBOYWl2ZSBCYXllcwpuYiA8LSBuYignbGMnLCBzdG1fZGF0YV9zdWIpCiMgT0RFIENob3ctTGl1IHdpdGggQUlDIHNjb3JlIChwZW5hbGl6ZWQgbG9nLWxpa2VsaWhvb2QpCm9kZV9jbF9haWMgPC0gdGFuX2NsKCdsYycsIHN0bV9kYXRhX3N1Yiwgc2NvcmUgPSAnYWljJykKIyBTZW1pLW5haXZlIEJheWVzIHdpdGggZm9yd2FyZCBzZXF1ZW50aWFsIHNlbGVjdGlvbiBhbmQgam9pbmluZyAoRlNTSikgYW5kCiMgNS1mb2xkIGNyb3NzLXZhbGlkYXRpb24KZnNzaiA8LSBmc3NqKCdsYycsIHN0bV9kYXRhX3N1YiwgayA9IDUsIGVwc2lsb24gPSAwKQoKcGxvdChvZGVfY2xfYWljKQoKCm5iIDwtIGxwKG5iLCBzdG1fZGF0YV9zdWIsIHNtb290aCA9IDAuMDEpCmF3bmIgPC0gbHAobmIsIHN0bV9kYXRhX3N1Yiwgc21vb3RoID0gMC4wMSwgYXduYl90cmVlcyA9IDEwLCBhd25iX2Jvb3RzdHJhcCA9IDAuNSkKbWFuYiA8LSBscChuYiwgc3RtX2RhdGFfc3ViLCBzbW9vdGggPSAwLjAxLCBtYW5iX3ByaW9yID0gMC41KQpvZGVfY2xfYWljIDwtIGJuYygndGFuX2NsJywgJ2xjJywgc3RtX2RhdGFfc3ViLCBzbW9vdGggPSAxLCBkYWdfYXJncyA9IGxpc3Qoc2NvcmUgPSAnYWljJykpCmxvZ0xpayhvZGVfY2xfYWljLCBzdG1fZGF0YV9zdWIpCkFJQyhvZGVfY2xfYWljLCBzdG1fZGF0YV9zdWIpCnAgPC0gcHJlZGljdChuYiwgc3RtX2RhdGFfc3ViKQphY2N1cmFjeShwLCBzdG1fZGF0YV9zdWIkbGMpCgpzZXQuc2VlZCgwKQpjdihvZGVfY2xfYWljLCBzdG1fZGF0YV9zdWIsIGsgPSAxMCkKY3Yob2RlX2NsX2FpYywgc3RtX2RhdGFfc3ViLCBrID0gMjAsIGRhZyA9IEZBTFNFLCBtZWFuID0gRkFMU0UpCmNtaSgndHh0X2NsYXNzJywgJ3NvY19jbCcsIHN0bV9kYXRhX3N1YiwgJ2xjJykKCgoKbGlicmFyeShtbHIpCm9kZV9jbF9haWNfbWxyIDwtIGFzX21scihvZGVfY2xfYWljLCBkYWcgPSBUUlVFLCBpZCA9ICJvZGVfY2xfYWljIikKCiMgNS1mb2xkIGNyb3NzLXZhbGlkYXRpb24KcmRlc2MgPSBtYWtlUmVzYW1wbGVEZXNjKCJDViIsIGl0ZXJzID0gMikKIyBzZXF1ZW50aWFsIGZsb2F0aW5nIGZvcndhcmQgc2VhcmNoCmN0cmwgPSBtYWtlRmVhdFNlbENvbnRyb2xTZXF1ZW50aWFsKG1ldGhvZCA9ICJzZnMiLCBhbHBoYSA9IDApCiMgV3JhcCBvZGVfY2xfYWljX21sciB3aXRoIGZlYXR1cmUgc2VsZWN0aW9uCm9kZV9jbF9haWNfbWxyX2ZzID0gbWFrZUZlYXRTZWxXcmFwcGVyKG9kZV9jbF9haWNfbWxyLCByZXNhbXBsaW5nID0gcmRlc2MsCmNvbnRyb2wgPSBjdHJsLCBzaG93LmluZm8gPSBGQUxTRSkKdCA8LSBtYWtlQ2xhc3NpZlRhc2soaWQgPSAic3RtX2RhdGFfc3ViIiwgZGF0YSA9IHN0bV9kYXRhX3N1YiwKdGFyZ2V0ID0gJ2xjJywgZml4dXAuZGF0YSA9ICJubyIsIGNoZWNrLmRhdGEgPSBGQUxTRSkKCnN1cHByZXNzV2FybmluZ3MoUk5HdmVyc2lvbigiMy41LjAiKSkKc2V0LnNlZWQoMCkKIyBTZWxlY3QgZmVhdHVyZXMKbW9kIDwtIHRyYWluKG9kZV9jbF9haWNfbWxyX2ZzLCB0YXNrID0gdCkKc2ZlYXRzIDwtIGdldEZlYXRTZWxSZXN1bHQobW9kKQpzZmVhdHMKCmBgYAoKCiMgUGl4ZWwgL0luZGV4IFZhbHVlIERlc2NyaXB0aW9uCjEgTm8gQ2hhbmdlCjIgQ2hhbmdlIGZyb20gb3IgdG8gV2F0ZXIKMyBDaGFuZ2UgZnJvbSBvciB0byBhbnkgb2YgdGhlIGZvdXIgVXJiYW4gY2xhc3NlcyAob3BlbiBzcGFjZTsgbG93LCBtZWRpdW0sIGFuZCBoaWdoIGludGVuc2l0eSkKNCBDaGFuZ2UgZnJvbSBIZXJiYWNlb3VzIFdldGxhbmQgdG8gV29vZHkgV2V0bGFuZCwgb3IgdmljZSB2ZXJzYQo1IENoYW5nZSBmcm9tIG9yIHRvIEhlcmJhY2VvdXMgV2V0bGFuZAo2IENoYW5nZSBmcm9tIEN1bHRpdmF0ZWQgQ3JvcHMgdG8gSGF5IC8gUGFzdHVyZSwgb3IgdmljZSB2ZXJzYQo3IENoYW5nZSBmcm9tIG9yIHRvIEN1bHRpdmF0ZWQgQ3JvcHMKOCBDaGFuZ2UgZnJvbSBvciB0byBIYXkgLyBQYXN0dXJlCjkgUGVyc2lzdGVudCBHcmFzc2xhbmQgYW5kIFNocnVibGFuZCBjaGFuZ2UuIFRoaXMgY2hhbmdlIGluZGV4IGF0dGVtcHRzIHRvIGlkZW50aWZ5IGNoYW5nZXMgdG8gcGVyc2lzdGVudCBHcmFzc2xhbmQgYW5kIFNocnVibGFuZCBhcmVhcywgYW5kIHRvIHNlcGFyYXRlIHRoZW0gZnJvbSB0cmFuc2l0aW9uYWwgc2hydWJsYW5kIGFyZWFzIHN1Y2ggYXMgcmVnZW5lcmF0aW5nIGZvcmVzdHMuCjEwIENoYW5nZSBmcm9tIG9yIHRvIEJhcnJlbgoxMSBDaGFuZ2UgZnJvbSBvciB0byBhbnkgb2YgdGhlIHRocmVlIEZvcmVzdCBjbGFzc2VzIChFdmVyZ3JlZW4sIERlY2lkdW91cywgYW5kIE1peGVkKQoxMiBDaGFuZ2UgZnJvbSBvciB0byBXb29keSBXZXRsYW5kCgoKIyBOYXRpb25hbCBMYW5kIENvdmVyIERhdGFiYXNlIENsYXNzIExlZ2VuZCBhbmQgRGVzY3JpcHRpb24KQ2xhc3NcIFZhbHVlIENsYXNzaWZpY2F0aW9uIERlc2NyaXB0aW9uCgojIyBXYXRlcgoxMSBPcGVuIFdhdGVyLSBhcmVhcyBvZiBvcGVuIHdhdGVyLCBnZW5lcmFsbHkgd2l0aCBsZXNzIHRoYW4gMjUlIGNvdmVyIG9mIHZlZ2V0YXRpb24Kb3Igc29pbC4KCjEyIFBlcmVubmlhbCBJY2UvU25vdy0gYXJlYXMgY2hhcmFjdGVyaXplZCBieSBhIHBlcmVubmlhbCBjb3ZlciBvZiBpY2UgYW5kL29yIHNub3csCmdlbmVyYWxseSBncmVhdGVyIHRoYW4gMjUlIG9mIHRvdGFsIGNvdmVyLgoKIyMgRGV2ZWxvcGVkCjIxIERldmVsb3BlZCwgT3BlbiBTcGFjZS0gYXJlYXMgd2l0aCBhIG1peHR1cmUgb2Ygc29tZSBjb25zdHJ1Y3RlZCBtYXRlcmlhbHMsIGJ1dAptb3N0bHkgdmVnZXRhdGlvbiBpbiB0aGUgZm9ybSBvZiBsYXduIGdyYXNzZXMuIEltcGVydmlvdXMgc3VyZmFjZXMgYWNjb3VudCBmb3IgbGVzcwp0aGFuIDIwJSBvZiB0b3RhbCBjb3Zlci4gVGhlc2UgYXJlYXMgbW9zdCBjb21tb25seSBpbmNsdWRlIGxhcmdlLWxvdCBzaW5nbGUtZmFtaWx5CmhvdXNpbmcgdW5pdHMsIHBhcmtzLCBnb2xmIGNvdXJzZXMsIGFuZCB2ZWdldGF0aW9uIHBsYW50ZWQgaW4gZGV2ZWxvcGVkIHNldHRpbmdzIGZvcgpyZWNyZWF0aW9uLCBlcm9zaW9uIGNvbnRyb2wsIG9yIGFlc3RoZXRpYyBwdXJwb3Nlcy4KCjIyIERldmVsb3BlZCwgTG93IEludGVuc2l0eS0gYXJlYXMgd2l0aCBhIG1peHR1cmUgb2YgY29uc3RydWN0ZWQgbWF0ZXJpYWxzIGFuZAp2ZWdldGF0aW9uLiBJbXBlcnZpb3VzIHN1cmZhY2VzIGFjY291bnQgZm9yIDIwJSB0byA0OSUgcGVyY2VudCBvZiB0b3RhbCBjb3Zlci4KVGhlc2UgYXJlYXMgbW9zdCBjb21tb25seSBpbmNsdWRlIHNpbmdsZS1mYW1pbHkgaG91c2luZyB1bml0cy4KCjIzIERldmVsb3BlZCwgTWVkaXVtIEludGVuc2l0eSAtYXJlYXMgd2l0aCBhIG1peHR1cmUgb2YgY29uc3RydWN0ZWQgbWF0ZXJpYWxzIGFuZAp2ZWdldGF0aW9uLiBJbXBlcnZpb3VzIHN1cmZhY2VzIGFjY291bnQgZm9yIDUwJSB0byA3OSUgb2YgdGhlIHRvdGFsIGNvdmVyLiBUaGVzZQphcmVhcyBtb3N0IGNvbW1vbmx5IGluY2x1ZGUgc2luZ2xlLWZhbWlseSBob3VzaW5nIHVuaXRzLgoKMjQgRGV2ZWxvcGVkIEhpZ2ggSW50ZW5zaXR5LWhpZ2hseSBkZXZlbG9wZWQgYXJlYXMgd2hlcmUgcGVvcGxlIHJlc2lkZSBvciB3b3JrIGluCmhpZ2ggbnVtYmVycy4gRXhhbXBsZXMgaW5jbHVkZSBhcGFydG1lbnQgY29tcGxleGVzLCByb3cgaG91c2VzIGFuZApjb21tZXJjaWFsL2luZHVzdHJpYWwuIEltcGVydmlvdXMgc3VyZmFjZXMgYWNjb3VudCBmb3IgODAlIHRvIDEwMCUgb2YgdGhlIHRvdGFsCmNvdmVyLgoKIyMgQmFycmVuCjMxIEJhcnJlbiBMYW5kIChSb2NrL1NhbmQvQ2xheSkgLSBhcmVhcyBvZiBiZWRyb2NrLCBkZXNlcnQgcGF2ZW1lbnQsIHNjYXJwcywgdGFsdXMsCnNsaWRlcywgdm9sY2FuaWMgbWF0ZXJpYWwsIGdsYWNpYWwgZGVicmlzLCBzYW5kIGR1bmVzLCBzdHJpcCBtaW5lcywgZ3JhdmVsIHBpdHMgYW5kIG90aGVyCmFjY3VtdWxhdGlvbnMgb2YgZWFydGhlbiBtYXRlcmlhbC4gR2VuZXJhbGx5LCB2ZWdldGF0aW9uIGFjY291bnRzIGZvciBsZXNzIHRoYW4gMTUlCm9mIHRvdGFsIGNvdmVyLgoKIyMgRm9yZXN0CjQxIERlY2lkdW91cyBGb3Jlc3QtIGFyZWFzIGRvbWluYXRlZCBieSB0cmVlcyBnZW5lcmFsbHkgZ3JlYXRlciB0aGFuIDUgbWV0ZXJzIHRhbGwsCmFuZCBncmVhdGVyIHRoYW4gMjAlIG9mIHRvdGFsIHZlZ2V0YXRpb24gY292ZXIuIE1vcmUgdGhhbiA3NSUgb2YgdGhlIHRyZWUgc3BlY2llcwpzaGVkIGZvbGlhZ2Ugc2ltdWx0YW5lb3VzbHkgaW4gcmVzcG9uc2UgdG8gc2Vhc29uYWwgY2hhbmdlLgoKNDIgRXZlcmdyZWVuIEZvcmVzdC0gYXJlYXMgZG9taW5hdGVkIGJ5IHRyZWVzIGdlbmVyYWxseSBncmVhdGVyIHRoYW4gNSBtZXRlcnMgdGFsbCwKYW5kIGdyZWF0ZXIgdGhhbiAyMCUgb2YgdG90YWwgdmVnZXRhdGlvbiBjb3Zlci4gTW9yZSB0aGFuIDc1JSBvZiB0aGUgdHJlZSBzcGVjaWVzCm1haW50YWluIHRoZWlyIGxlYXZlcyBhbGwgeWVhci4gQ2Fub3B5IGlzIG5ldmVyIHdpdGhvdXQgZ3JlZW4gZm9saWFnZS4KCjQzIE1peGVkIEZvcmVzdC0gYXJlYXMgZG9taW5hdGVkIGJ5IHRyZWVzIGdlbmVyYWxseSBncmVhdGVyIHRoYW4gNSBtZXRlcnMgdGFsbCwgYW5kCmdyZWF0ZXIgdGhhbiAyMCUgb2YgdG90YWwgdmVnZXRhdGlvbiBjb3Zlci4gTmVpdGhlciBkZWNpZHVvdXMgbm9yIGV2ZXJncmVlbiBzcGVjaWVzCmFyZSBncmVhdGVyIHRoYW4gNzUlIG9mIHRvdGFsIHRyZWUgY292ZXIuCgojIyBTaHJ1YmxhbmQKNTEgRHdhcmYgU2NydWItIEFsYXNrYSBvbmx5IGFyZWFzIGRvbWluYXRlZCBieSBzaHJ1YnMgbGVzcyB0aGFuIDIwIGNlbnRpbWV0ZXJzIHRhbGwKd2l0aCBzaHJ1YiBjYW5vcHkgdHlwaWNhbGx5IGdyZWF0ZXIgdGhhbiAyMCUgb2YgdG90YWwgdmVnZXRhdGlvbi4gVGhpcyB0eXBlIGlzIG9mdGVuCmNvLWFzc29jaWF0ZWQgd2l0aCBncmFzc2VzLCBzZWRnZXMsIGhlcmJzLCBhbmQgbm9uLXZhc2N1bGFyIHZlZ2V0YXRpb24uCgo1MiBTaHJ1Yi9TY3J1Yi0gYXJlYXMgZG9taW5hdGVkIGJ5IHNocnViczsgbGVzcyB0aGFuIDUgbWV0ZXJzIHRhbGwgd2l0aCBzaHJ1YiBjYW5vcHkKdHlwaWNhbGx5IGdyZWF0ZXIgdGhhbiAyMCUgb2YgdG90YWwgdmVnZXRhdGlvbi4gVGhpcyBjbGFzcyBpbmNsdWRlcyB0cnVlIHNocnVicywgeW91bmcKdHJlZXMgaW4gYW4gZWFybHkgc3VjY2Vzc2lvbmFsIHN0YWdlIG9yIHRyZWVzIHN0dW50ZWQgZnJvbSBlbnZpcm9ubWVudGFsIGNvbmRpdGlvbnMuCgojIyBIZXJiYWNlb3VzCjcxIEdyYXNzbGFuZC9IZXJiYWNlb3VzLSBhcmVhcyBkb21pbmF0ZWQgYnkgZ3JhbWFub2lkIG9yIGhlcmJhY2VvdXMgdmVnZXRhdGlvbiwKZ2VuZXJhbGx5IGdyZWF0ZXIgdGhhbiA4MCUgb2YgdG90YWwgdmVnZXRhdGlvbi4gVGhlc2UgYXJlYXMgYXJlIG5vdCBzdWJqZWN0IHRvCmludGVuc2l2ZSBtYW5hZ2VtZW50IHN1Y2ggYXMgdGlsbGluZywgYnV0IGNhbiBiZSB1dGlsaXplZCBmb3IgZ3JhemluZy4KCjcyIFNlZGdlL0hlcmJhY2VvdXMtIEFsYXNrYSBvbmx5IGFyZWFzIGRvbWluYXRlZCBieSBzZWRnZXMgYW5kIGZvcmJzLCBnZW5lcmFsbHkKZ3JlYXRlciB0aGFuIDgwJSBvZiB0b3RhbCB2ZWdldGF0aW9uLiBUaGlzIHR5cGUgY2FuIG9jY3VyIHdpdGggc2lnbmlmaWNhbnQgb3RoZXIKZ3Jhc3NlcyBvciBvdGhlciBncmFzcyBsaWtlIHBsYW50cywgYW5kIGluY2x1ZGVzIHNlZGdlIHR1bmRyYSwgYW5kIHNlZGdlIHR1c3NvY2sKdHVuZHJhLgoKNzMgTGljaGVucy0gQWxhc2thIG9ubHkgYXJlYXMgZG9taW5hdGVkIGJ5IGZydXRpY29zZSBvciBmb2xpb3NlIGxpY2hlbnMgZ2VuZXJhbGx5CmdyZWF0ZXIgdGhhbiA4MCUgb2YgdG90YWwgdmVnZXRhdGlvbi4KCjc0IE1vc3MtIEFsYXNrYSBvbmx5IGFyZWFzIGRvbWluYXRlZCBieSBtb3NzZXMsIGdlbmVyYWxseSBncmVhdGVyIHRoYW4gODAlIG9mIHRvdGFsCnZlZ2V0YXRpb24uCgojIyBQbGFudGVkL0N1bHRpdmF0ZWQKODEgUGFzdHVyZS9IYXktYXJlYXMgb2YgZ3Jhc3NlcywgbGVndW1lcywgb3IgZ3Jhc3MtbGVndW1lIG1peHR1cmVzIHBsYW50ZWQgZm9yCmxpdmVzdG9jayBncmF6aW5nIG9yIHRoZSBwcm9kdWN0aW9uIG9mIHNlZWQgb3IgaGF5IGNyb3BzLCB0eXBpY2FsbHkgb24gYSBwZXJlbm5pYWwKY3ljbGUuIFBhc3R1cmUvaGF5IHZlZ2V0YXRpb24gYWNjb3VudHMgZm9yIGdyZWF0ZXIgdGhhbiAyMCUgb2YgdG90YWwgdmVnZXRhdGlvbi4KCjgyIEN1bHRpdmF0ZWQgQ3JvcHMgLWFyZWFzIHVzZWQgZm9yIHRoZSBwcm9kdWN0aW9uIG9mIGFubnVhbCBjcm9wcywgc3VjaCBhcyBjb3JuLApzb3liZWFucywgdmVnZXRhYmxlcywgdG9iYWNjbywgYW5kIGNvdHRvbiwgYW5kIGFsc28gcGVyZW5uaWFsIHdvb2R5IGNyb3BzIHN1Y2ggYXMKb3JjaGFyZHMgYW5kIHZpbmV5YXJkcy4gQ3JvcCB2ZWdldGF0aW9uIGFjY291bnRzIGZvciBncmVhdGVyIHRoYW4gMjAlIG9mIHRvdGFsCnZlZ2V0YXRpb24uIFRoaXMgY2xhc3MgYWxzbyBpbmNsdWRlcyBhbGwgbGFuZCBiZWluZyBhY3RpdmVseSB0aWxsZWQuCgojIyBXZXRsYW5kcwo5MCBXb29keSBXZXRsYW5kcy0gYXJlYXMgd2hlcmUgZm9yZXN0IG9yIHNocnVibGFuZCB2ZWdldGF0aW9uIGFjY291bnRzIGZvciBncmVhdGVyCnRoYW4gMjAlIG9mIHZlZ2V0YXRpdmUgY292ZXIgYW5kIHRoZSBzb2lsIG9yIHN1YnN0cmF0ZSBpcyBwZXJpb2RpY2FsbHkgc2F0dXJhdGVkIHdpdGgKb3IgY292ZXJlZCB3aXRoIHdhdGVyLgoKCiMgRGVub21pbmF0aW9uIHBoIHJhbmdlClVsdHJhIGFjaWQgPCAzLjUKRXh0cmVtZWx5IGFjaWQgMy414oCTNC40ClZlcnkgc3Ryb25nbHkgYWNpZCA0LjXigJM1LjAKU3Ryb25nbHkgYWNpZCA1LjHigJM1LjUKTW9kZXJhdGVseSBhY2lkIDUuNuKAkzYuMApTbGlnaHRseSBhY2lkIDYuMeKAkzYuNQpOZXV0cmFsIDYuNuKAkzcuMwpTbGlnaHRseSBhbGthbGluZSA3LjTigJM3LjgKTW9kZXJhdGVseSBhbGthbGluZSA3LjnigJM4LjQKU3Ryb25nbHkgYWxrYWxpbmUgOC414oCTOS4wClZlcnkgc3Ryb25nbHkgYWxrYWxpbmUgPiA5LjAKCgoKIyBTT0MgY2xhc3NlcyAoNCBjbGFzc2VzKQo8IS0tIDAtMSAtLT4KPCEtLSAxLTIgLS0+CjwhLS0gMi0zIC0tPgo8IS0tID4zIC0tPgoKCgojIERiIGNsYXNzZXMKPCEtLSA8MSA9IHZlcnkgbG9vc2UgLS0+CjwhLS0gMS0xLjIgPSBsb29zZSAtLT4KPCEtLSAxLjItMS40ID0gbm9ybWFsIC0tPgo8IS0tIDEuNC0xLjYgPSBoYXJkIC0tPgo8IS0tID4xLjYgPSBjb21wYWN0IC0tPgoKCgpgYGB7cn0KdGV4dHVyZXMgPC0gYygiU2FuZCIsIkxvYW15IHNhbmQiLCJTYW5keSBsb2FtIiwiTG9hbSIsIlNpbHQgbG9hbSIsCiAgICAgICAgICAgICAgICAiU2lsdCIsIlNhbmR5IGNsYXkgbG9hbSIsIkNsYXkgbG9hbSIsIlNpbHR5IGNsYXkgbG9hbSIsCiAgICAgICAgICAgICAgICAiU2FuZHkgY2xheSIsIlNpbHR5IGNsYXkiLCJDbGF5IikKCnBoX2NsYXNzIDwtIGZ1bmN0aW9uKHBoKXsKaWYoaXMubmEocGgpKXsKICBjbGFzcyA9IE5BCn1lbHNlIGlmKHBoIDw9IDMuNSl7CiAgY2xhc3MgPSAnVWx0cmEgYWNpZCcKfWVsc2UgaWYocGggPiAzLjUgJiBwaCA8PSA0LjUpewogIGNsYXNzID0gJ0V4dHJlbWVseSBhY2lkJwp9ZWxzZSBpZihwaCA+IDQuNSAmIHBoIDw9IDUpewogIGNsYXNzID0gJ1Zlcnkgc3Ryb25nbHkgYWNpZCcKfWVsc2UgaWYocGggPiA1ICYgcGggPCA1LjYpewogIGNsYXNzID0gJ1N0cm9uZ2x5IGFjaWQnCn1lbHNlIGlmKHBoID49IDUuNiAmIHBoIDw9IDYpewogIGNsYXNzID0gJ01vZGVyYXRlbHkgYWNpZCcKfWVsc2UgaWYocGggPiA2ICYgcGggPD0gNi41KXsKICBjbGFzcyA9ICdTbGlnaHRseSBhY2lkJwp9ZWxzZSBpZihwaCA+IDYuNSAmIHBoIDw9IDcuMyl7CiAgY2xhc3MgPSAnTmV1dHJhbCcKfWVsc2UgaWYocGggPiA3LjMgJiBwaCA8PSA3LjgpewogIGNsYXNzID0gJ1NsaWdodGx5IGFsa2FsaW5lJwp9ZWxzZSBpZihwaCA+IDcuOCAmIHBoIDw9IDguNCl7CiAgY2xhc3MgPSAnTW9kZXJhdGVseSBhbGthbGluZScKfWVsc2UgaWYocGggPiA4LjQgJiBwaCA8PSA5KXsKICBjbGFzcyA9ICdTdHJvbmdseSBhbGthbGluZScKfWVsc2UgaWYocGggPiA5ICYgcGggPD0gOSl7CiAgY2xhc3MgPSAnVmVyeSBzdHJvbmdseSBhbGthbGluZScKfWVsc2Uge2NsYXNzID0gTkF9CnJldHVybihjbGFzcykKfQoKc29jX2NsYXNzIDwtIGZ1bmN0aW9uKHNvYyl7CmlmKGlzLm5hKHNvYykpewogIGNsYXNzID0gTkEKfWVsc2UgaWYoc29jIDw9IDEpewogIGNsYXNzID0gJ2xvdycKfWVsc2UgaWYoc29jID4gMSAmIHNvYyA8PSAyKXsKICBjbGFzcyA9ICdtb2RlcmF0ZScKfWVsc2UgaWYoc29jID4gMiAmIHNvYyA8PSAzKXsKICBjbGFzcyA9ICdoaWdoJwp9ZWxzZSBpZihzb2MgPiAzKXsKICBjbGFzcyA9ICd2ZXJ5IGhpZ2gnCn1lbHNlIHtjbGFzcyA9IE5BfQpyZXR1cm4oY2xhc3MpCn0KCmRiX2NsYXNzIDwtIGZ1bmN0aW9uKERiKXsKaWYoaXMubmEoRGIpKXsKICBjbGFzcyA9IE5BCn1lbHNlIGlmKERiIDw9IDEpewogIGNsYXNzID0gJ3ZlcnkgbG9vc2UnCn1lbHNlIGlmKERiID4gMSAmIERiIDw9IDEuMil7CiAgY2xhc3MgPSAnbG9vc2UnCn1lbHNlIGlmKERiID4gMS4yICYgRGIgPD0gMS40KXsKICBjbGFzcyA9ICdub3JtYWwnCn1lbHNlIGlmKERiID4gMS40ICYgRGIgPD0gMS42KXsKICBjbGFzcyA9ICdoYXJkJwp9ZWxzZSBpZihEYiA+IDEuNil7CiAgY2xhc3MgPSAnY29tcGFjdCcKfQpyZXR1cm4oY2xhc3MpCn0KCmdldHR0IDwtIGZ1bmN0aW9uKHNhbmQsIHNpbHQsIGNsYXkpewogIGlmKGlzLm5hKHNhbmQpIHwgaXMubmEoc2lsdCkgfCBpcy5uYShjbGF5KSl7CiAgICB4ID0gTkEKICB9IGVsc2UgaWYoKHNpbHQgKyAxLjUgKiBjbGF5KSA8IDE1KXsKICAgIHggPSAiU2FuZCIKICB9IGVsc2UgaWYoKHNpbHQgKyAxLjUgKiBjbGF5KSA+PSAxNSAmIChzaWx0ICsgMi4wICogY2xheSkgPCAzMCl7CiAgICB4ID0gIkxvYW15IHNhbmQiCiAgfSBlbHNlIGlmKChjbGF5ID49IDcpICYgKGNsYXkgPD0gMjApICYgKHNhbmQgPiA1MikgJiAoKHNpbHQgKyAyLjAgKiBjbGF5KSA+PSAzMCkpewogICAgeCA9ICJTYW5keSBsb2FtIgogIH0gZWxzZSBpZigoY2xheSA8IDcpICYgKHNpbHQgPCA1MCkgJiAoKHNpbHQgKyAyLjAgKiBjbGF5KSA+PSAzMCkpewogICAgeCA9ICJTYW5keSBsb2FtIgogIH0gZWxzZSBpZigoY2xheSA+PSA3KSAmIChjbGF5IDw9IDI3KSAmIChzaWx0ID49IDI4KSAmIChzaWx0IDwgNTApICYgKHNhbmQgPD0gNTIpKXsKICAgIHggPSAiTG9hbSIKICB9IGVsc2UgaWYoKChzaWx0ID49IDUwKSAmIChjbGF5ID49IDEyKSAmIChjbGF5IDwgMjcpKSB8ICgoc2lsdCA+PSA1MCkgJiAoc2lsdCA8IDgwKSAmIChjbGF5IDwgMTIpKSl7CiAgICB4ID0gIlNpbHQgbG9hbSIKICB9IGVsc2UgaWYoKHNpbHQgPj0gODApICYgKGNsYXkgPCAxMikpewogICAgeCA9ICJTaWx0IgogIH0gZWxzZSBpZigoY2xheSA+PSAyMCkgJiAoY2xheSA8IDM1KSAmIChzaWx0IDwgMjgpICYgKHNhbmQgPiA0NSkpewogICAgeCA9ICJTYW5keSBjbGF5IGxvYW0iCiAgfSBlbHNlIGlmKChjbGF5ID49IDI3KSAmIChjbGF5IDwgNDApICYgKHNhbmQgPiAyMCkgJiAoc2FuZCA8PSA0NSkpewogICAgeCA9ICJDbGF5IGxvYW0iCiAgfSBlbHNlIGlmKChjbGF5ID49IDI3KSAmIChjbGF5IDwgNDApICYgKHNhbmQgPD0gMjApKXsKICAgIHggPSAiU2lsdHkgY2xheSBsb2FtIgogIH0gZWxzZSBpZigoY2xheSA+PSAzNSkgJiAoc2FuZCA+PSA0NSkpewogICAgeCA9ICJTYW5keSBjbGF5IgogIH0gZWxzZSBpZigoY2xheSA+PSA0MCkgJiAoc2lsdCA+PSA0MCkpewogICAgeCA9ICJTaWx0eSBjbGF5IgogIH0gZWxzZSBpZigoY2xheSA+PSA0MCkgJiAoc2FuZCA8PSA0NSkgJiAoc2lsdCA8IDQwKSl7CiAgICB4ID0gIkNsYXkiCiAgfQogIHJldHVybih4KQp9CgpgYGAKCg==